﻿///////////////////////////////////////////////////////////////////////////////
/// Copyright (c) by longshuang@msn.cn 2014.
/// All rights reserved.
///
/// @File	: Engine.Compress.hpp
/// @Brief	: 一个简单的Zip压缩工具类
/// @Author	: Leo Zhao <longshuang@msn.cn>
/// @Date	: 2015-08-21
///
/// CHANGELOG
///		2015-09-03	修改Zip文件遍历方式
/// 	2015-08-21	初版提交
///////////////////////////////////////////////////////////////////////////////
#ifndef		__ENGINE_COMPRESS_INCLUDE__
#define		__ENGINE_COMPRESS_INCLUDE__

#include	<cstdlib>
#include	<cstdint>
#include	<vector>

struct mz_zip_archive_tag;

namespace Engine {

	struct ZipItem {
		char	szFile[256];
		bool	bDir;
		size_t	uSize;
	};

	class ZipIterator {
		typedef std::vector<ZipItem>::iterator ItemIterator;

	public:
		ZipIterator(std::vector<ZipItem> & rList) : _iItor(rList.begin()), _iEnd(rList.end()) {}
		virtual ~ZipIterator() {}

		inline					operator bool() const { return _iItor != _iEnd; }
		inline void				operator++() { _iItor++; }
		inline ZipItem *		Info() { return &(*_iItor); }

	private:
		ItemIterator	_iItor;
		ItemIterator	_iEnd;
	};
	
	class Zip {
	public:
		enum EState {
			Success		= 0,	//! 成功
			StreamEnd	= 1,	//! 读取完成
			NeedDict	= 2,	//!	需要重新建立字典
			ErrorNo		= -1,	//! 文件操作失败
			StreamError	= -2,	//!	流操作失败，输入错误
			DataError	= -3,	//!	输入数据不正确
			MemError	= -4,	//!	内存不足
			BufError	= -5,	//!	输出空间不足
			VerError	= -6		//!	解压使用的版本与压缩使用的版本不兼容
		};
		
	public:
		Zip();
		virtual ~Zip();

		/// @Brief	: 粗略计算一下压缩后需要的空间
		/// @Param	: uSizeSrc	原始数据地址
		/// @Return	: 返回压缩后需要的最大空间
		static size_t	CalcCompressSize(size_t uSizeSrc);

		/// @Brief	: 压缩数据块
		/// @Param	: pDst		压缩后数据存储位置，需要自己申请。大小为CalcCompressSize(uSizeSrc)
		/// @Param	: uSizeDst	传入压缩后数据存储区的大小，压缩完成后存放最终所使用的大小
		/// @Param	: pSrc		传入原始数据存储地址
		/// @Param	: uSizeSrc	传入原始数据大小
		/// @Return	: 返回压缩操作结果。
		static EState	Compress(char * pDst, size_t & uSizeDst, const char * pSrc, size_t uSizeSrc);
		
		/// @Brief	: 解压缩数据块
		/// @Param	: pDst		解压缩后数据存储位置，需要自己申请。大小需要自己根据实际情况决定
		/// @Param	: uSizeDst	传入解压缩后数据存储区的大小，解压缩完成后存放最终所使用的大小
		/// @Param	: pSrc		传入原始数据存储地址
		/// @Param	: uSizeSrc	传入原始数据大小
		/// @Return	: 返回解压缩操作结果。
		static EState	Uncompress(char * pDst, size_t & uSizeDst, const char * pSrc, size_t uSizeSrc);
		
		/// @Brief	: 加载一个Zip文件
		/// @Param	: szPath	加载文件的路径
		/// @Return	: 返回是否成功加载Zip文件
		bool			FromFile(const char * szPath);

		/// @Brief	: 加载一个Zip文件（从内存中）
		/// @Param	: pData		Zip文件的内容存储地址
		/// @Param	: uSize		Zip文件的内容大小
		/// @Return	: 返回是否成功加载Zip文件
		bool			FromMem(const char * pData, size_t uSize);

		/// @Brief	: 当前Zip压缩包中所包含的文件（包含文件夹）数
		/// @Param	: NONE
		/// @Return	: 返回当前Zip压缩包中所包含的文件（包含文件夹）数
		size_t			Count() { return _vInfos.size(); }

		/// @Brief	: 得到Zip中某个文件的信息
		/// @Param	: szItem	文件在Zip中的路径
		/// @Return	: 该文件的信息地址，如果不存在指定文件，返回NULL
		ZipItem *		GetItemInfo(const char * szItem);

		/// @Brief	: 遍历Zip文件
		/// @Param	: NONE
		/// @Return	: 遍历器
		ZipIterator		Iterator() { return ZipIterator(_vInfos); }
		
		/// @Brief	: 从Zip中解压出一个文件到指定内存空间中
		/// @Param	: szItem	文件名
		/// @Param	: pMem		内容存储空间地址
		/// @Param	: uSize		该内存空间的大小
		/// @Return	: 返回是否成功
		bool			Extra(const char * szItem, char * pMem, size_t uSize);
		
		/// @Brief	: 关闭当前正在读取的Zip文件
		/// @Param	: NONE
		/// @Return	: NONE
		void			Close();
		
	private:
		Zip(const Zip &) = delete;
		Zip &			operator=(const Zip &) = delete;

	private:
		mz_zip_archive_tag *	_pZip;
		bool					_bValid;
		std::vector<ZipItem>	_vInfos;
	};

}

#endif//!	__ENGINE_COMPRESS_INCLUDE__